home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / ACQUISITION.STX < prev    next >
Encoding:
Text File  |  1999-03-23  |  9.3 KB  |  278 lines

  1. Acquisition
  2.  
  3.   "Copyright (C) 1996-1998, Digital Creations":COPYRIGHT.html.
  4.  
  5.   Acquisition [1] is a mechanism that allows objects to obtain
  6.   attributes from their environment.  It is similar to inheritence,
  7.   except that, rather than traversing an inheritence hierarchy
  8.   to obtain attributes, a containment hierarchy is traversed.
  9.  
  10.   The "ExtensionClass":ExtensionClass.html. release includes mix-in
  11.   extension base classes that can be used to add acquisition as a
  12.   feature to extension subclasses.  These mix-in classes use the
  13.   context-wrapping feature of ExtensionClasses to implement
  14.   acquisition. Consider the following example::
  15.  
  16.     import ExtensionClass, Acquisition
  17.  
  18.     class C(ExtensionClass.Base):
  19.       color='red'
  20.  
  21.     class A(Acquisition.Implicit):
  22.  
  23.       def report(self):
  24.         print self.color
  25.  
  26.     a=A()
  27.     c=C()
  28.     c.a=A()
  29.  
  30.     c.a.report() # prints 'red'
  31.  
  32.     d=C()
  33.     d.color='green'
  34.     d.a=a
  35.  
  36.     d.a.report() # prints 'green'
  37.  
  38.     a.report() # raises an attribute error
  39.  
  40.   The class 'A' inherits acquisition behavior from
  41.   'Acquisition.Implicit'.  The object, 'a', "has" the color of
  42.   objects 'c' and 'd' when it is accessed through them, but it
  43.   has no color by itself.  The object 'a' obtains attributes
  44.   from it's environment, where it's environment is defined by
  45.   the access path used to reach 'a'.
  46.  
  47.   Acquisition wrappers
  48.  
  49.     When an object that supports acquisition is accessed through
  50.     an extension class instance, a special object, called an
  51.     acquisition wrapper, is returned.  In the example above, the
  52.     expression 'c.a' returns an acquisition wrapper that
  53.     contains references to both 'c' and 'a'.  It is this wrapper
  54.     that performs attribute lookup in 'c' when an attribute
  55.     cannot be found in 'a'.
  56.  
  57.     Aquisition wrappers provide access to the wrapped objects
  58.     through the attributes 'aq_parent', 'aq_self', 'aq_base'.  
  59.     In the example above, the expressions::
  60.       
  61.        'c.a.aq_parent is c'
  62.  
  63.     and::
  64.  
  65.        'c.a.aq_self is a'
  66.  
  67.     both evaluate to true, but the expression::
  68.  
  69.        'c.a is a'
  70.  
  71.     evaluates to false, because the expression 'c.a' evaluates
  72.     to an acquisition wrapper around 'c' and 'a', not 'a' itself.
  73.  
  74.     The attribute 'aq_base' is similar to 'aq_self'.  Wrappers may be
  75.     nested and 'aq_self' may be a wrapped object.  The 'aq_base'
  76.     attribute is the underlying object with all wrappers removed.
  77.  
  78.   Acquisition Control
  79.  
  80.     Two styles of acquisition are supported in the current
  81.     ExtensionClass release, implicit and explicit aquisition.
  82.   
  83.     Implicit acquisition
  84.     
  85.       Implicit acquisition is so named because it searches for
  86.       attributes from the environment automatically whenever an
  87.       attribute cannot be obtained directly from an object or
  88.       through inheritence.
  89.   
  90.       An attribute may be implicitly acquired if it's name does
  91.       not begin with an underscore, '_'.
  92.   
  93.       To support implicit acquisition, an object should inherit
  94.       from the mix-in class 'Acquisition.Implicit'.
  95.   
  96.     Explicit Acquisition
  97.   
  98.       When explicit acquisition is used, attributes are not
  99.       automatically obtained from the environment.  Instead, the
  100.       method 'aq_aquire' must be used, as in::
  101.   
  102.     print c.a.aq_acquire('color')
  103.   
  104.       To support explicit acquisition, an object should inherit
  105.       from the mix-in class 'Acquisition.Explicit'.
  106.  
  107.     Controlled Acquisition
  108.  
  109.       A class (or instance) can provide attribute by attribute control
  110.       over acquisition.  This is done by:
  111.  
  112.       - subclassing from 'Acquisition.Explicit', and
  113.  
  114.       - setting all attributes that should be acquired to the special
  115.         value: 'Acquisition.Acquired'.  Setting an attribute to this
  116.         value also allows inherited attributes to be overridden with
  117.         acquired ones.
  118.  
  119.     For example, in::
  120.  
  121.       class C(Acquisition.Explicit):
  122.          id=1
  123.          secret=2
  124.          color=Acquisition.Acquired
  125.          __roles__=Acquisition.Acquired
  126.  
  127.     The *only* attributes that are automatically acquired from
  128.     containing objects are 'color', and '__roles__'.  Note also
  129.     that the '__roles__' attribute is acquired even though it's
  130.     name begins with an underscore.  In fact, the special
  131.     'Acquisition.Acquired' value can be used in
  132.     'Acquisition.Implicit' objects to implicitly acquire selected
  133.     objects that smell like private objects.
  134.  
  135.     Filtered Acquisition
  136.  
  137.       The acquisition method, 'aq_acquire', accepts two optional
  138.       arguments. The first of the additional arguments is a
  139.       "filtering" function that is used when considering whether to
  140.       acquire an object.  The second of the additional arguments is an
  141.       object that is passed as extra data when calling the filtering
  142.       function and which defaults to 'None'.
  143.  
  144.       The filter function is called with five arguments:
  145.  
  146.       - The object that the 'aq_acquire' method was called on,
  147.  
  148.       - The object where an object was found,
  149.  
  150.       - The name of the object, as passed to 'aq_acquire',
  151.  
  152.       - The object found, and
  153.  
  154.       - The extra data passed to 'aq_acquire'.
  155.  
  156.       If the filter returns a true object that the object found is
  157.       returned, otherwise, the acquisition search continues.
  158.  
  159.       For example, in::
  160.  
  161.     from Acquisition import Explicit
  162.     
  163.     class HandyForTesting:
  164.         def __init__(self, name): self.name=name
  165.         def __str__(self):
  166.         return "%s(%s)" % (self.name, self.__class__.__name__)
  167.         __repr__=__str__
  168.     
  169.     class E(Explicit, HandyForTesting): pass
  170.     
  171.     class Nice(HandyForTesting):
  172.         isNice=1
  173.         def __str__(self):
  174.         return HandyForTesting.__str__(self)+' and I am nice!'
  175.         __repr__=__str__
  176.     
  177.     a=E('a')
  178.     a.b=E('b')
  179.     a.b.c=E('c')
  180.     a.p=Nice('spam')
  181.     a.b.p=E('p')
  182.     
  183.     def find_nice(self, ancestor, name, object, extra):
  184.         return hasattr(object,'isNice') and object.isNice
  185.     
  186.     print a.b.c.aq_acquire('p', find_nice)
  187.  
  188.       The filtered acquisition in the last line skips over the first
  189.       attribute it finds with the name 'p', because the attribute
  190.       doesn't satisfy the condition given in the filter. The output of
  191.       the last line is::
  192.  
  193.         spam(Nice) and I am nice!
  194.  
  195.   Acquisition and methods
  196.  
  197.     Python methods of objects that support acquisition can use
  198.     acquired attributes as in the 'report' method of the first example
  199.     above.  When a Python method is called on an object that is
  200.     wrapped by an acquisition wrapper, the wrapper is passed to the
  201.     method as the first argument.  This rule also applies to
  202.     user-defined method types and to C methods defined in pure mix-in
  203.     classes.
  204.  
  205.     Unfortunately, C methods defined in extension base classes that
  206.     define their own data structures, cannot use aquired attributes at
  207.     this time.  This is because wrapper objects do not conform to the
  208.     data structures expected by these methods.
  209.  
  210.   Acquiring Acquiring objects
  211.  
  212.     Consider the following example::
  213.  
  214.       from Acquisition import Implicit
  215.       
  216.       class C(Implicit):
  217.       def __init__(self, name): self.name=name
  218.       def __str__(self):
  219.           return "%s(%s)" % (self.name, self.__class__.__name__)
  220.       __repr__=__str__
  221.       
  222.       a=C("a")
  223.       a.b=C("b")
  224.       a.b.pref="spam"
  225.       a.b.c=C("c")
  226.       a.b.c.color="red"
  227.       a.b.c.pref="eggs"
  228.       a.x=C("x")
  229.  
  230.       o=a.b.c.x
  231.  
  232.     The expression 'o.color' might be expected to return '"red"'. In
  233.     earlier versions of ExtensionClass, however, this expression
  234.     failed.  Acquired acquiring objects did not acquire from the
  235.     environment they were accessed in, because objects were only
  236.     wrapped when they were first found, and were not rewrapped as they
  237.     were passed down the acquisition tree.
  238.  
  239.     In the current release of ExtensionClass, the expression "o.color"
  240.     does indeed return '"red"'.
  241.  
  242.     When searching for an attribute in 'o', objects are searched in
  243.     the order 'x', 'a', 'b', 'c'. So, for example, the expression,
  244.     'o.pref' returns '"spam"', not '"eggs"'.  In earlier releases of
  245.     ExtensionClass, the attempt to get the 'pref' attribute from 'o'
  246.     would have failed.
  247.  
  248.     If desired, the current rules for looking up attributes in complex
  249.     expressions can best be understood through repeated application of
  250.     the '__of__' method:
  251.  
  252.     'a.x' -- 'x.__of__(a)'
  253.  
  254.     'a.b' -- 'b.__of__(a)'
  255.  
  256.     'a.b.x' -- 'x.__of__(a).__of__(b.__of__(a))'
  257.  
  258.     'a.b.c' -- 'c.__of__(b.__of__(a))'
  259.  
  260.     'a.b.c.x' --
  261.         'x.__of__(a).__of__(b.__of__(a)).__of__(c.__of__(b.__of__(a)))'
  262.  
  263.     and by keeping in mind that attribute lookup in a wrapper
  264.     is done by trying to lookup the attribute in the wrapped object
  265.     first and then in the parent object.  In the expressions above
  266.     involving the '__of__' method, lookup proceeds from left to right.
  267.  
  268.     Note that heuristics are used to avoid most of the repeated
  269.     lookups. For example, in the expression: 'a.b.c.x.foo', the object
  270.     'a' is searched no more than once, even though it is wrapped three
  271.     times.
  272.  
  273. .. [1] Gil, J., Lorenz, D., 
  274.    "Environmental Acquisition--A New Inheritance-Like Abstraction Mechanism",
  275.    http://www.bell-labs.com/people/cope/oopsla/Oopsla96TechnicalProgramAbstracts.html#GilLorenz, 
  276.    OOPSLA '96 Proceedings, ACM SIG-PLAN, October, 1996
  277.      
  278.